/**
 * @Author: 陆昭华 1361176289@qq.com
 * @Date: 2023-06-18 11:05:36
 * @LastEditors: 陆昭华 1361176289@qq.com
 * @LastEditTime: 2023-06-21 16:01:19
 * @FilePath: \xiaolu-p\index.js
 * @Description:
 * @Copyright (c) 2023 by 陆昭华 email: 1361176289@qq.com, All Rights Reserved.
 **/
export default {
	/**
	 * @description : 校验身份证号是否合规（18位、15位）
	 * @param        {String|Number} value
	 * @return       {Boolean} true-合规 false-不合规
	 * @example      checkPsidno('110101199003074274') // true
	 */
	checkPsidno(value) {
		const psidno = String(value);
		// 1.校验身份证号格式和长度
		const regPsidno = /^(^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$)|(^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])((\d{4})|\d{3}[X])$)$/;
		if (!regPsidno.test(psidno)) {
			return false;
		}
		// 2.校验前两位的省份编码是否正确
		const province = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江 ", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北 ", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏 ", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外" };
		if (!province[Number(psidno.slice(0, 2))]) {
			return false;
		}
		// 3.校验出生日期
		if (psidno.length === 15) {
			// 15位号码 省（2位）市（2位）县（2位）年（2位）月（2位）日（2位）校验码（3位）
			const reg = new RegExp(/^(\d{6})(\d{2})(\d{2})(\d{2})(\d{3})$/);
			const arrSplit = psidno.match(reg);
			// 15位号码在年份前补 19 或 20
			const year = Number(arrSplit[2].charAt(0)) > 0 ? "19" + arrSplit[2] : "20" + arrSplit[2];
			const month = arrSplit[3];
			const day = arrSplit[4];
			if (!validateBirthday(year, month, day)) {
				return false;
			}
		} else if (psidno.length === 18) {
			// 18位号码 省（2位）市（2位）县（2位）年（4位）月（2位）日（2位）校验码（4位）
			const reg = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
			const arrSplit = psidno.match(reg);
			const year = arrSplit[2];
			const month = arrSplit[3];
			const day = arrSplit[4];
			if (!validateBirthday(year, month, day)) {
				return false;
			}
		} else {
			return false;
		}
		// 校验出生日期是否合理
		function validateBirthday(year, month, day) {
			year = Number(year); // 年
			month = Number(month); // 月
			day = Number(day); // 日
			const nowTime = new Date().getTime(); // 当前时间戳
			const birthTime = new Date(`${year}-${month}-${day}`).getTime(); // 获取出生日期的时间戳
			// 不能是明天出生的吧
			if (birthTime > nowTime) {
				return false;
			}
			// 一般人活不到150岁吧
			const nowYear = new Date().getFullYear();
			if (nowYear - year > 150) {
				return false;
			}
			// 不能是13月出生的吧
			if (month < 1 || month > 12) {
				return false;
			}
			// 不能是2月30号、4月31号、5月32号出生的吧
			const date = new Date(year, month, 0); // 获取当月的最后一天
			if (day < 1 || day > date.getDate()) {
				return false;
			}
			return true;
		}
		// 4.18位号码校验生成的校验码
		if (psidno.length === 18) {
			const Wi = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; // 加权因子
			const parity = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"]; // 校验码
			let sum = 0;
			for (let i = 0; i < 17; i++) {
				sum += Number(psidno.charAt(i)) * Wi[i];
			}
			if (parity[sum % 11] !== psidno[17]) {
				return false;
			}
		}
		return true;
	},

	/**
	 *  检测护照是否正确
	 *
	 * @param {String} value
	 *  @returns {Boolean} true 合法 false 不合法
	 * @example checkPassport(value) // true
	 */
	checkPassport(value) {
		const reg = /(^[EeKkGgDdSsPpHh]\d{8}$)|(^(([Ee][a-fA-F])|([DdSsPp][Ee])|([Kk][Jj])|([Mm][Aa])|(1[45]))\d{7}$)/;
		return reg.test(value);
	},

	/**
	 * 验证手机号合法性
	 * @param {String} value
	 * @returns {Boolean} true 合法 false 不合法
	 * @example checkPhone('18888888888') // true
	 */
	checkPhone(value) {
		const reg = /^(?:(?:\+|00)86)?1(?:(?:3[\d])|(?:4[5-79])|(?:5[0-35-9])|(?:6[5-7])|(?:7[0-8])|(?:8[\d])|(?:9[189]))\d{8}$/;
		return reg.test(value);
	},

	/**
	 * 日期格式化
	 *
	 * @param {String} time 时间
	 * @param {String} pattern 格式化模板 '{y}-{m}-{d} {h}:{i}:{s}'
	 * @returns {String} 格式化后的时间
	 * @example parseTime('2018-1-29 10:30:30', '{y}-{m}-{d} {h}:{i}:{s}') // 2018-01-29 10:30:30
	 */
	parseTime(time, pattern) {
		if (arguments.length === 0 || !time) {
			return null;
		}
		const format = pattern || "{y}-{m}-{d} {h}:{i}:{s}";
		let date;
		if (typeof time === "object") {
			date = time;
		} else {
			if (typeof time === "string" && /^[0-9]+$/.test(time)) {
				time = parseInt(time);
			} else if (typeof time === "string") {
				time = time
					.replace(new RegExp(/-/gm), "/")
					.replace("T", " ")
					.replace(new RegExp(/\.[\d]{3}/gm), "");
			}
			if (typeof time === "number" && time.toString().length === 10) {
				time = time * 1000;
			}
			date = new Date(time);
		}
		const formatObj = {
			y: date.getFullYear(),
			m: date.getMonth() + 1,
			d: date.getDate(),
			h: date.getHours(),
			i: date.getMinutes(),
			s: date.getSeconds(),
			a: date.getDay(),
		};
		const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
			let value = formatObj[key];
			// Note: getDay() returns 0 on Sunday
			if (key === "a") {
				return ["日", "一", "二", "三", "四", "五", "六"][value];
			}
			if (result.length > 0 && value < 10) {
				value = "0" + value;
			}
			return value || 0;
		});
		return time_str;
	},

	/**
    * 触底加载
    * 
    * @param {Element} el dom 支持传入id和class或ref
    * @param {function} callback 回调函数 
    * @param {object} config 配置项(可选) - threshold: 0-1, - rootMargin: '0px 0px 600px 0px' -root 默认为根节点 即 视口  也可以传入dom 但必须是要观察的元素父级
    * @example bottomLoading('.loading', () => {
        console.log('触底了')
    }, { threshold: 0, rootMargin: '0px 0px 600px 0px' })
    */

	//    默认配置
	bottomLoadingObj: {
		threshold: 0,
		rootMargin: "0px 0px 600px 0px",
	},

	bottomLoading(el, callback, config = this.bottomLoadingObj) {
		const isel = el instanceof HTMLElement;
		let className = undefined;
		let id = undefined;
		if (!isel) {
			className = document.getElementsByClassName(el.startsWith(".") ? el.replace(".", "") : el);
			id = document.getElementById(el.startsWith("#") ? el.replace("#", "") : el);
		}
		if (config.root) {
			if (config.root instanceof HTMLElement && !config.root.contains(el)) throw new Error("root元素必须包含观察的元素");
			throw new Error("root必须是一个dom");
		}
		const ob = new IntersectionObserver((entries) => {
			if (entries[0].isIntersecting) {
				callback.apply(this);
			}
		}, config);
		if (isel) return ob.observe(el);
		className.length > 0 ? ob.observe(className[0]) : ob.observe(id);
	},

	/**
	 * 检测是否中文汉字
	 * @param {*} value  需要检测的值
	 * @returns {Boolean} true 合法 false 不合法
	 * @example isChinese('我是中国人') // true
	 */
	isChinese(value) {
		const reg = /^(?:[\u3400-\u4DB5\u4E00-\u9FEA\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879][\uDC00-\uDFFF]|\uD869[\uDC00-\uDED6\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0])+$/;
		return reg.test(value);
	},
	/**
	 * storge封装
	 */
	storage: {
		set(key, value) {
			if (typeof value === "object") {
				value = JSON.stringify(value);
			}
			localStorage.setItem(key, value);
		},
		get(key) {
			return localStorage.getItem(key);
		},
		remove(key) {
			localStorage.removeItem(key);
		},
		clear() {
			localStorage.clear();
		},
	},
	/**
	 * cookie封装
	 */
	cookie: {
		set(key, value, day) {
			const date = new Date();
			date.setDate(date.getDate() + day);
			document.cookie = `${key}=${value};expires=${date}`;
		},
		get(key) {
			const arr = document.cookie.split("; ");
			for (let i = 0; i < arr.length; i++) {
				const arr2 = arr[i].split("=");
				if (arr2[0] === key) {
					return arr2[1];
				}
			}
			return "";
		},
		remove(key) {
			this.set(key, "", -1);
		},
		clear() {
			const keys = document.cookie.match(/[^ =;]+(?=\=)/g);
			if (keys) {
				for (let i = keys.length; i--; ) {
					document.cookie = `${keys[i]}=0;expires=${new Date(0).toUTCString()}`;
				}
			}
		},
	},
	/**
	 * 全屏
	 */
	fullScreen() {
		if (!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) {
			if (document.documentElement.requestFullscreen) {
				document.documentElement.requestFullscreen();
			} else if (document.documentElement.msRequestFullscreen) {
				document.documentElement.msRequestFullscreen();
			} else if (document.documentElement.mozRequestFullScreen) {
				document.documentElement.mozRequestFullScreen();
			} else if (document.documentElement.webkitRequestFullscreen) {
				document.documentElement.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
			}
		}
	},
	/**
	 * 退出全屏
	 */
	exitFullscreen() {
		if (document.exitFullscreen) {
			document.exitFullscreen();
		} else if (document.msExitFullscreen) {
			document.msExitFullscreen();
		} else if (document.mozCancelFullScreen) {
			document.mozCancelFullScreen();
		} else if (document.webkitExitFullscreen) {
			document.webkitExitFullscreen();
		}
	},
	/**
	 * @description 局部dom进入全屏
	 * @param {Element} el
	 */
	launchFullScreen(el) {
		const isel = el instanceof HTMLElement;
		let className = undefined;
		let id = undefined;
		if (!isel) {
			className = document.getElementsByClassName(el.startsWith(".") ? el.replace(".", "") : el);
			id = document.getElementById(el.startsWith("#") ? el.replace("#", "") : el);
		}

		if (isel ? el.requestFullscreen : className.length > 0 ? className[0].requestFullscreen : id.requestFullscreen) {
			el.requestFullscreen();
		} else if (isel ? el.mozRequestFullScreen : className.length > 0 ? className[0].mozRequestFullScreen : id.mozRequestFullScreen) {
			el.mozRequestFullScreen();
		} else if (isel ? el.webkitRequestFullscreen : className.length > 0 ? className[0].webkitRequestFullscreen : id.webkitRequestFullscreen) {
			el.webkitRequestFullscreen();
		} else if (isel ? el.msRequestFullscreen : className.length > 0 ? className[0].msRequestFullscreen : id.msRequestFullscreen) {
			el.msRequestFullscreen();
		}
	},
	/**
	 * @description 局部dom退出全屏
	 * @param {Element} el
	 */
	exitlaunchFullScreen(el) {
		const isel = el instanceof HTMLElement;
		let className = undefined;
		let id = undefined;
		if (!isel) {
			className = document.getElementsByClassName(el.startsWith(".") ? el.replace(".", "") : el);
			id = document.getElementById(el.startsWith("#") ? el.replace("#", "") : el);
		}
		if (isel ? el.exitFullscreen : className.length > 0 ? className[0].exitFullscreen : id.exitFullscreen) {
			el.exitFullscreen();
		} else if (isel ? el.mozCancelFullScreen : className.length > 0 ? className[0].mozCancelFullScreen : id.mozCancelFullScreen) {
			el.mozCancelFullScreen();
		} else if (isel ? el.webkitExitFullscreen : className.length > 0 ? className[0].webkitExitFullscreen : id.webkitExitFullscreen) {
			el.webkitExitFullscreen();
		} else if (isel ? el.msExitFullscreen : className.length > 0 ? className[0].msExitFullscreen : id.msExitFullscreen) {
			el.msExitFullscreen();
		}
	},
	/**
	 * 防抖立即执行
	 * @param {Function} fn 要执行的函数
	 * @param {String | Number} delay 延迟执行时间
	 * @param {Boolean} now 是否立即执行
	 * @param {callback} callback 回调函数
	 */
	debounce(fn, delay, now = false, callback) {
		var t = null;
		// 将内部函数定义为函数字面量
		// 大家应该知道函数本质上其实也是一个对象
		// 可以通过 debounced instanceof Object来验证
		var debounced = function () {
			var _self = this,
				args = arguments;

			if (t) {
				clearTimeout(t);
			}
			// 如果需要立即执行目标函数即now -> true
			if (now) {
				/**
				 * 记录当前是否存在定时器
				 * 因为now设置为true之后的每一次执行都会进入这个判断分支
				 * 我们需要判断当前是否是真的"第一次"进入执行
				 */
				var trigger = !t;
				// 记录完trigger之后, 设置一个定时器
				// 定时器的目的是在延迟之后清除t
				// 以便延迟时间之后的进入判断为"第一次进入"
				t = setTimeout(function () {
					clearTimeout(t);
					t = null;
				}, delay);
				// 第一次进入执行
				if (trigger) {
					// 立即执行目标函数
					fn.apply(_self, args);
				} else {
					// 若不是第一次执行则执行防抖操作
					t = setTimeout(function () {
						callback(fn.apply(_self, args));
					}, delay);
				}
			} else {
				// 非立即执行情况，正常执行防抖操作
				t = setTimeout(function () {
					callback(fn.apply(_self, args));
				}, delay);
			}
		};

		// 清除当前作用域中的定时器
		debounced.remove = function () {
			clearTimeout(t);
			t = null;
		};
	},

	/**
	 * 节流
	 * @param {function} fn
	 * @param {String | Number} delay
	 * @param {callback} callback
	 * @returns
	 */
	throttle(fn, delay, callback) {
		var t = null,
			// 获取到节流函数绑定时的时间戳
			begin = new Date().getTime();

		var throttled = function () {
			var _self = this,
				args = arguments,
				now = new Date().getTime();

			// 清除上一次绑定的延迟事件
			// 本次触发会再次绑定
			clearTimeout(t);

			if (now - begin > delay) {
				// 当前触发时间与上次触发时间之差大于延迟时间
				// 直接响应事件
				callback(fn.apply(_self, args));
				begin = now;
			} else {
				t = setTimeout(function () {
					callback(fn.apply(_self, args));
				}, delay);
			}
		};

		throttled.remove = function () {
			clearTimeout(t);
			t = null;
		};
		return throttled;
	},
	/**
	 * 判断对象是否为空
	 *
	 * @param {object} obj 要检测的对象
	 * @param {Boolean} isdeep 是否深度遍历 默认false
	 * @returns {Array} 返回一个数组，数组中是对象中为空的属性  如果为空则代表象中的属性全都不为空
	 */
	isEmptyObject(obj, exclude = [], isdeep = false) {
		const isobj = obj instanceof Object;
		let arr = [];
		if (isobj) {
			Object.keys(obj).forEach((key) => {
				const keyisobj = obj[key] instanceof Object;
				if (isdeep && keyisobj) {
					arr = arr.concat(this.isEmptyObject(obj[key], exclude, true));
				} else {
					if (!exclude.includes(key) && !obj[key]) arr.push(key);
				}
			});
		} else {
			throw new Error("传入的值必须是一个对象");
		}
		return arr;
	},
	/**
	 * object对象清空
	 * @param {Object} obj
	 */
	clearObject(obj = {}, exclude = []) {
		Object.keys(obj).forEach((key) => {
			if (!exclude.includes(key)) obj[key] = undefined;
		});
	},
	/**
	 * 金额千分位
	 * @param {String | Number} num
	 * @returns
	 */
	toThousands(num) {
		return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, "$1,");
	},
	/**
	 * @description 判断时间是多久之前
	 * @param {String | Number} dateTimeStamp
	 * @returns
	 */
	getDateDiff(dateTimeStamp) {
		// 时间字符串转时间戳
		var timestamp = new Date(dateTimeStamp).getTime();
		var minute = 1000 * 60;
		var hour = minute * 60;
		var day = hour * 24;
		var halfamonth = day * 15;
		var month = day * 30;
		var year = day * 365;
		var now = new Date().getTime();
		var diffValue = now - timestamp;
		var result;
		if (diffValue < 0) {
			return;
		}
		var yearC = diffValue / year;
		var monthC = diffValue / month;
		var weekC = diffValue / (7 * day);
		var dayC = diffValue / day;
		var hourC = diffValue / hour;
		var minC = diffValue / minute;
		if (yearC >= 1) {
			result = "" + parseInt(yearC) + "年前";
		} else if (monthC >= 1) {
			result = "" + parseInt(monthC) + "月前";
		} else if (weekC >= 1) {
			result = "" + parseInt(weekC) + "周前";
		} else if (dayC >= 1) {
			result = "" + parseInt(dayC) + "天前";
		} else if (hourC >= 1) {
			result = "" + parseInt(hourC) + "小时前";
		} else if (minC >= 1) {
			result = "" + parseInt(minC) + "分钟前";
		} else result = "刚刚";
		return result;
	},
	/**
	 * @description 路由跳转
	 * @param {Object} url
	 * @param {Object} t
	 * @param {Object} num
	 * @param {Object} Login
	 */
	link(url, t = 1, num = 1, Login = uni.$lu?.config?.checkLogin?.isCheck) {
		//要判断是否登录
		if (Login) {
			if (!uni.getStorageSync(uni.$lu?.config?.checkLogin?.checkText)) {
				uni.navigateTo({
					url: uni.$lu?.config?.checkLogin?.checkBackUrl
				})
				return
			}
		}
	
		const stauts = {
			1: 'navigateTo',
			2: 'redirectTo',
			3: 'reLaunch',
			4: 'switchTab',
			5: 'navigateBack'
		}
	
		if (t == 5) {
			return uni[stauts[t]]({
				url: url,
				delta: num
			})
		}
	
		uni[stauts[t]]({
			url: url
		})
	},
	/**
	 * @description 存储 同步方法
	 * @param {Object} $sSyn
	 */
	sSyn(k, v) {
		uni.setStorageSync(k, v)
	},
	
	/**
	 * @description 获取存储 同步方法
	 * @param {Object} $gSyn
	 */
	gSyn(v) {
		return uni.getStorageSync(v)
	},
	
	/**
	 * 异步获取存储方法
	 * 
	 * @param {Object} v
	 */
	gS(v) {
		return new Promise((resolve, reject) => {
			uni.getStorage({
				key: v,
				success(res) {
					resolve(res.data)
				}
			})
		})
	},
	
	/**
	 * @description 删除存储 同步方法
	 * @param {Object} $rSyn
	 */
	rSyn(v) {
		if (!v) return uni.$lu.toast('请填写删除的key,方法:uni.$rSyn');
		uni.removeStorageSync(v);
	},
	
	/**
	 * 清楚全部缓存
	 */
	cSyn() {
		uni.clearStorage()
	}
};
